#pragma once
#include <iostream>
#include <string>
#include <strings.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <functional>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
const int gnum=1024;

namespace Server
{
    using namespace std;
    static const string defaultIP="0.0.0.0";
    enum {USAGE_ERR=1,SOCKET_ERR,BIND_ERR};
    class udpServer
    {
    public:
        udpServer(const uint16_t& port,const string ip=defaultIP)
        :port_(port),ip_(ip) {}
        ~udpServer() {}
        void initServer()
        {
            // 1.创建socket
            sockfd_=socket(AF_INET,SOCK_DGRAM,0); // IPv4 UDP
            if(sockfd_==-1)
            {
                cerr<<"socket error : "<<errno<<" : "<<strerror(errno)<<endl;
                exit(SOCKET_ERR);
            }
            // 2.绑定port
            struct sockaddr_in local;
            bzero(&local,sizeof(local)); 
            local.sin_family=AF_INET; // 设置IPv4
            local.sin_port=htons(port_); //设置端口号 主机字节序转网络节序
            //local.sin_addr.s_addr=inet_addr(ip_.c_str()); //sin_addr是个结构体 其内s_addr是用于存储IPv4地址 是uint32_t类型变量
            local.sin_addr.s_addr=INADDR_ANY; //任意地址bind 服务器真实写法
            int n=bind(sockfd_,(struct sockaddr*)&local,sizeof(local));
            if(n==-1)
            {
                cerr<<"socket error : "<<errno<<" : "<<strerror(errno)<<endl;
                exit(BIND_ERR);
            }


        }
        void start()
        {
            char buffer[gnum];
            while(true)
            {
                struct sockaddr_in peer;
                socklen_t len=sizeof(peer);
                ssize_t s=recvfrom(sockfd_,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len); // peer填充发送方地址的 sockaddr 结构体(输出参数)
                if(s>0) //返回到的字节数                                                             // len 输入时为 src_addr 的大小 返回时是实际地址长度(输入/输出参数)   
                {
                    buffer[s]=0;
                    string clientIP=inet_ntoa(peer.sin_addr); //将 IPv4 的网络字节序地址转换为点分十进制字符串格式 参数为 sockaddr_in内的sin_addr结构体
                    uint16_t clientPort=ntohs(peer.sin_port); //从网络字节序的 端口号(sin_port) 转换为主机字节序的uint16_t类型
                    string message=buffer;

                    cout<<clientIP<<"["<<clientPort<<"]"<<"# "<<message<<endl;

                }
                sleep(1);
            }

        }

    private:
        uint16_t port_;
        std::string ip_;
        int sockfd_;


    };

}